package com.pzb.wxpay.service.impl;
import com.pzb.order.domain.OdOrder;
import com.pzb.order.service.IOdOrderService;
import com.pzb.wechat.domain.WechatApplet;
import com.pzb.wechat.domain.WechatNotify;
import com.pzb.wechat.domain.WechatRechargeLog;
import com.pzb.wechat.domain.WechatUserAccount;
import com.pzb.wechat.service.IWechatAppletService;
import com.pzb.wechat.service.IWechatNotifyService;
import com.pzb.wechat.service.IWechatRechargeLogService;
import com.pzb.wechat.service.IWechatUserAccountService;
import com.pzb.wxpay.service.IWxPayService;
import com.pzb.wxpay.util.PayUtil;
import com.pzb.wxpay.util.WechatConfig;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import javax.servlet.http.HttpServletRequest;
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.math.BigDecimal;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;

/**
 * 小程序用户Service业务层处理
 * 
 * @author Mr_Wu
 * @date 2022-01-12
 */
@Service
public class WxPayServiceImpl implements IWxPayService
{
    @Autowired
    IWechatAppletService appletService;
    @Autowired
    IWechatUserAccountService userAccountService;
    @Autowired
    IOdOrderService orderService;
    @Autowired
    IWechatNotifyService wechatNotifyService;
    @Autowired
    IWechatRechargeLogService rechargeLogService;

    public final String notify_url = "https://www.bluesharksys.com/uni-api/wxPay/wxNotify";
    //交易类型，小程序支付的固定值为JSAPI
    public static final String TRADETYPE = "JSAPI";
    //微信统一下单接口地址
    public static final String pay_url = "https://api.mch.weixin.qq.com/pay/unifiedorder";

    /**
     * 微信支付统一下单
     *
     * @param
     * @return
     */
    public Map pay(String extAppid,String openid,String ip,String body,String out_trade_no,String price){
        Map<String, Object> payMap = new HashMap<String, Object>();//返回给小程序端需要的参数
        //获取商户信息
        WechatApplet applet = appletService.selectWechatAppletByAppid(extAppid);
        try {
            //生成的随机字符串
            String nonce_str = PayUtil.getRandomStringByLength(32);
            //组装参数，用户生成统一下单接口的签名
            Map<String, String> packageParams = new HashMap<>();
            packageParams.put("appid", extAppid);
            packageParams.put("mch_id", applet.getMchId());
            packageParams.put("nonce_str", nonce_str);
            packageParams.put("body", body);
            packageParams.put("out_trade_no", out_trade_no);//商户订单号,自己的订单ID
            packageParams.put("total_fee", price);//支付金额，这边需要转成字符串类型，否则后面的签名会失败
            packageParams.put("spbill_create_ip", ip);
            packageParams.put("notify_url", notify_url);//支付成功后的回调地址
            packageParams.put("trade_type", TRADETYPE);//支付方式
            packageParams.put("openid", openid);//用户的openID，自己获取
            String prestr = PayUtil.createLinkString(packageParams); // 把数组所有元素，按照“参数=参数值”的模式用“&”字符拼接成字符串
            System.err.println("----------调用统一下单接口-------");
            //MD5运算生成签名，这里是第一次签名，用于调用统一下单接口
            String mysign = PayUtil.sign(prestr, applet.getMchKey(), "utf-8").toUpperCase();
            //拼接统一下单接口使用的xml数据，要将上一步生成的签名一起拼接进去
            String xml = "<xml>" + "<appid>" + extAppid + "</appid>"
                    + "<body><![CDATA[" + body + "]]></body>"
                    + "<mch_id>" + applet.getMchId() + "</mch_id>"
                    + "<nonce_str>" + nonce_str + "</nonce_str>"
                    + "<notify_url>" + notify_url + "</notify_url>"
                    + "<openid>" + openid + "</openid>"
                    + "<out_trade_no>" + out_trade_no + "</out_trade_no>"
                    + "<spbill_create_ip>" + ip + "</spbill_create_ip>"
                    + "<total_fee>" + price + "</total_fee>"//支付的金额，单位：分
                    + "<trade_type>" + TRADETYPE + "</trade_type>"
                    + "<sign>" + mysign + "</sign>"
                    + "</xml>";

            //调用统一下单接口，并接受返回的结果
            String result = PayUtil.httpRequest(pay_url, "POST", xml);
            System.err.println("----------result:" + result);
            // 将解析结果存储在HashMap中
            Map map = PayUtil.doXMLParse(result);
            String return_code = (String) map.get("return_code");//返回状态码
            String result_code = (String) map.get("result_code");//返回状态码
            String err_code = (String) map.get("err_code");//返回状态码
            String err_code_des = (String) map.get("err_code_des");//返回状态码
            if (return_code.equals("SUCCESS") || return_code.equals(result_code)) {
                String prepay_id = (String) map.get("prepay_id");//返回的预付单信息
                payMap.put("nonceStr", nonce_str);
                payMap.put("package", "prepay_id=" + prepay_id);
                Long timeStamp = System.currentTimeMillis() / 1000;
                payMap.put("timeStamp", timeStamp + "");//这边要将返回的时间戳转化成字符串，不然小程序端调用wx.requestPayment方法会报签名错误
                //拼接签名需要的参数
                String stringSignTemp = "appId=" + extAppid+ "&nonceStr=" + nonce_str + "&package=prepay_id=" + prepay_id + "&signType=MD5&timeStamp=" + timeStamp;
                //再次签名，这个签名用于小程序端调用wx.requesetPayment方法
                String paySign = PayUtil.sign(stringSignTemp, applet.getMchKey(), "utf-8").toUpperCase();
                payMap.put("paySign", paySign);
            } else {
                System.err.println("----------统一下单失败-------");
                return payMap;
            }
            //	OrderService.insert(payOperation);
            payMap.put("appid", extAppid);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return payMap;

    }

    @Override
    public String wxNotify(HttpServletRequest request) throws Exception{
        BufferedReader br = new BufferedReader(new InputStreamReader(request.getInputStream()));
        String line = null;
        StringBuilder sb = new StringBuilder();
        while ((line = br.readLine()) != null) {
            sb.append(line);
        }
        br.close();
        //sb为微信返回的xml
        String notityXml = sb.toString();
        String resXml = "";
        Map map = PayUtil.doXMLParse(notityXml);
        String returnCode = (String) map.get("return_code");
        if ("SUCCESS".equals(returnCode)) {
            //验证签名是否正确
            Map<String, String> validParams = PayUtil.paraFilter(map);  //回调验签时需要去除sign和空值参数
            String prestr = PayUtil.createLinkString(validParams);
            //根据微信官网的介绍，此处不仅对回调的参数进行验签，还需要对返回的金额与系统订单的金额进行比对等
            if (PayUtil.verify(prestr, (String) map.get("sign"), WechatConfig.key, "utf-8")) {
                /**此处添加自己的业务逻辑代码start**/
                //注意要判断微信支付重复回调，支付成功后微信会重复的进行回调
                String transaction_id = (String) map.get("transaction_id");
                String nonce_str = (String) map.get("nonce_str");
                String bank_type = (String) map.get("bank_type");
                String openid = (String) map.get("openid");
                String sign = (String) map.get("sign");
                String fee_type = (String) map.get("fee_type");
                String mch_id = (String) map.get("mch_id");
                String cash_fee = (String) map.get("cash_fee");
                String out_trade_no = (String) map.get("out_trade_no");
                String appid = (String) map.get("appid");
                String total_fee = (String) map.get("total_fee");
                String trade_type = (String) map.get("trade_type");
                String time_end = (String) map.get("time_end");

                if(out_trade_no.startsWith("BL")){ //如果是余额充值
                    WechatUserAccount account = userAccountService.selectWechatUserAccountByOpenId(openid,appid);
                    //查询余额充值订单记录
                    WechatRechargeLog rechargeLog = rechargeLogService.selectWechatRechargeLogByOrderNo(out_trade_no);
                    //计算余额
                    String balance =new BigDecimal(account.getBalance()).add(new BigDecimal(rechargeLog.getBalanceAmount())).toString();
                    account.setBalance(balance);
                    userAccountService.updateWechatUserAccount(account);
                    //修改充值订单状态为已支付
                    rechargeLogService.setRechargeIsPay(out_trade_no);
                }else if(out_trade_no.startsWith("GD")){ //订单支付
                    OdOrder order = orderService.selectOdOrderByOrderCode(out_trade_no);
                    order.setPayAmount(order.getPayTotalAmount());
                    order.setPaymentMethod("1");
                    order.setPayTime(new Date());
                    order.setPayStatus("1");
                    //如果自提
                    if("1".equals(order.getDeliveryMethod())){
                        //设为待提货状态
                        order.setOrderStatus("1");
                    }
                    orderService.updateOdOrder(order);
                }
                //存储回调记录
                WechatNotify notify = new WechatNotify();
                notify.setTransactionId(transaction_id);
                notify.setNonceStr(nonce_str);
                notify.setBankType(bank_type);
                notify.setOpenid(openid);
                notify.setSign(sign);
                notify.setFeeType(fee_type);
                notify.setMchId(mch_id);
                notify.setCashFee(Integer.parseInt(cash_fee));
                notify.setOutTradeNo(out_trade_no);
                notify.setAppid(appid);
                notify.setTotalFee(Integer.parseInt(total_fee));
                notify.setTradeType(trade_type);
                notify.setTimeEnd(Long.parseLong(time_end));
                wechatNotifyService.insertWechatNotify(notify);
                /**此处添加自己的业务逻辑代码end**/
                //通知微信服务器已经支付成功
                resXml = "<xml>" + "<return_code><![CDATA[SUCCESS]]></return_code>"
                        + "<return_msg><![CDATA[OK]]></return_msg>" + "</xml> ";
            }
        } else {
            resXml = "<xml>" + "<return_code><![CDATA[FAIL]]></return_code>"
                    + "<return_msg><![CDATA[报文为空]]></return_msg>" + "</xml> ";
        }
        return resXml;
    }


}
